﻿using Microsoft.Win32;
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.Principal;

namespace Infrastructure.Utils.Helpers
{
    /// <summary>
    /// 系统用户账户控制
    /// </summary>
    public static class UacHelper
    {
        public enum TOKEN_INFORMATION_CLASS
        {
            TokenUser = 1,
            TokenGroups,
            TokenPrivileges,
            TokenOwner,
            TokenPrimaryGroup,
            TokenDefaultDacl,
            TokenSource,
            TokenType,
            TokenImpersonationLevel,
            TokenStatistics,
            TokenRestrictedSids,
            TokenSessionId,
            TokenGroupsAndPrivileges,
            TokenSessionReference,
            TokenSandBoxInert,
            TokenAuditPolicy,
            TokenOrigin,
            TokenElevationType,
            TokenLinkedToken,
            TokenElevation,
            TokenHasRestrictions,
            TokenAccessInformation,
            TokenVirtualizationAllowed,
            TokenVirtualizationEnabled,
            TokenIntegrityLevel,
            TokenUIAccess,
            TokenMandatoryPolicy,
            TokenLogonSid,
            MaxTokenInfoClass
        }
        public enum TOKEN_ELEVATION_TYPE
        {
            TokenElevationTypeDefault = 1,
            TokenElevationTypeFull,
            TokenElevationTypeLimited
        }
        private const string uacRegistryKey = "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System";
        private const string uacRegistryValue = "EnableLUA";
        private static uint STANDARD_RIGHTS_READ = 131072u;
        private static uint TOKEN_QUERY = 8u;
        private static uint TOKEN_READ = UacHelper.STANDARD_RIGHTS_READ | UacHelper.TOKEN_QUERY;
        public static bool IsUacEnabled
        {
            get
            {
                RegistryKey registryKey = Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System", false);
                return registryKey.GetValue("EnableLUA").Equals(1);
            }
        }
        public static bool IsProcessElevated
        {
            get
            {
                if (!UacHelper.IsUacEnabled)
                {
                    WindowsIdentity current = WindowsIdentity.GetCurrent();
                    WindowsPrincipal windowsPrincipal = new WindowsPrincipal(current);
                    return windowsPrincipal.IsInRole(WindowsBuiltInRole.Administrator);
                }
                IntPtr tokenHandle;
                if (!UacHelper.OpenProcessToken(Process.GetCurrentProcess().Handle, UacHelper.TOKEN_READ, out tokenHandle))
                {
                    throw new ApplicationException("Could not get process token.  Win32 Error Code: " + Marshal.GetLastWin32Error());
                }
                UacHelper.TOKEN_ELEVATION_TYPE tOKEN_ELEVATION_TYPE = UacHelper.TOKEN_ELEVATION_TYPE.TokenElevationTypeDefault;
                int num = Marshal.SizeOf((int)tOKEN_ELEVATION_TYPE);
                uint num2 = 0u;
                IntPtr intPtr = Marshal.AllocHGlobal(num);
                bool tokenInformation = UacHelper.GetTokenInformation(tokenHandle, UacHelper.TOKEN_INFORMATION_CLASS.TokenElevationType, intPtr, (uint)num, out num2);
                if (tokenInformation)
                {
                    tOKEN_ELEVATION_TYPE = (UacHelper.TOKEN_ELEVATION_TYPE)Marshal.ReadInt32(intPtr);
                    return tOKEN_ELEVATION_TYPE == UacHelper.TOKEN_ELEVATION_TYPE.TokenElevationTypeFull;
                }
                throw new ApplicationException("Unable to determine the current elevation.");
            }
        }
        [DllImport("advapi32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool OpenProcessToken(IntPtr ProcessHandle, uint DesiredAccess, out IntPtr TokenHandle);
        [DllImport("advapi32.dll", SetLastError = true)]
        public static extern bool GetTokenInformation(IntPtr TokenHandle, UacHelper.TOKEN_INFORMATION_CLASS TokenInformationClass, IntPtr TokenInformation, uint TokenInformationLength, out uint ReturnLength);
    }
}
